import java.io.*;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Random;
import java.lang.Math;
import java.lang.String;

class THM{
	
	static double roundPot;
	
	public static void main(String args[]) throws IOException{
		GameRunner gr = new GameRunner();
		
		/*
		// start
		
		// open up standard input
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String s;
		System.out.println("Let the games begin" + "\n");
		
		System.out.println("What is your name");
		s = br.readLine();
		Player user = new Player(s);
		
		boolean quit = false;
		boolean quitRound = false;
		int opponents = 0;
		int resp;
		int resp2;
		double currBet = 0;;
		Card burn;
		double smallBlind = 10.00;
		double bigBlind = 15.00;
		while (!quit){
			
			getNumOpponenetsAndInitializePlayers(opponents, user);
			/*
			System.out.println("How many opponents would you like to have at your table");
			s = br.readLine();
			opponents = Integer.parseInt(s);
			Player[] players = new Player[opponents+1];
		
			players[0] = user;
			// initialize opponents
			for ( int i = 1; i < opponents+1; i++){
				players[i] = new Player("Player" + i);
			}
			*/
		
			// play out rounds
			int ptrToDealer = 1; // points to dealer
			double b = 0;
			roundPot = 0;
			quitRound = false;
			int dealingPtr = 0;
			int bettingPtr = 0;
			Card[] ftr;    // for holding flop, turn and river
			while( !quitRound ){
				ftr = new Card[5];
				roundPot = 0;
				Deck d = new Deck();
				d.shuffleDeck();
				int ptrToCurr = ptrToDealer;	// points to current player
				
				System.out.println("Dealer is:" + players[ptrToDealer].getName());
				
				blinds( smallBlind, bigBlind, currBet, players, ptrToCurr, opponents);
				/*
				// small blind
				ptrToCurr = getNextPlayer(ptrToCurr, opponents);
				if ( ptrToCurr == 0 ){ 	// if it is the user
					System.out.println("The Small blind is " + smallBlind + " would you like to enter (1), or fold now(2).");
					s = br.readLine();
					b = (double)Integer.parseInt(s);
					if ( b == 1 ){
						players[0].placeBet(smallBlind);
						roundPot = roundPot + players[0].getBet();
						currBet = players[0].getBet();
					}
					else{
						players[0].fold();
						System.out.println("You choose not enter this round");
						// find an ai that can do hte small blind isntead of the user
						// 		we are guaranteed to have at least 3 people
						while( players[ptrToCurr].getMoney() < smallBlind){
							ptrToCurr = getNextPlayer(ptrToCurr, opponents);
						}
						players[ptrToCurr].placeBet(smallBlind);
						roundPot = roundPot + players[ptrToCurr].getBet();
						currBet = players[ptrToCurr].getBet();
					}	
					
					System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[0].getBet() + " for Small Blind");
				}	
				else {		// if it is an AI
					while( players[ptrToCurr].getMoney() < smallBlind){
						ptrToCurr = getNextPlayer(ptrToCurr, opponents);
					}
					players[ptrToCurr].placeBet( smallBlind );	// for now bets qrtr of his money
					roundPot = roundPot + players[ptrToCurr].getBet();
					currBet = players[ptrToCurr].getBet();
					System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[ptrToCurr].getBet() + " for Small Blind");
				}
				
				
				// big blind 
				int foldOrBet = 0;
				ptrToCurr = getNextPlayer(ptrToCurr, opponents);
				// if it is the user
				if ( ptrToCurr == 0 ){ 	// if it is the user
					System.out.println("The Big blind is " + bigBlind + " would you like to enter (1), or fold now(2).");
					s = br.readLine();
					b = (double)Integer.parseInt(s);
					if ( b == 1 ){
						players[0].placeBet(bigBlind);
						roundPot = roundPot + players[0].getBet();
						currBet = players[0].getBet();
					}
					else{
						players[0].fold();
						System.out.println("You choose not enter this round");
						// find an ai that can do hte small blind isntead of hte user
						// 		we are guaranteed to have at least 3 people
						while( players[ptrToCurr].getMoney() < bigBlind){
							ptrToCurr = getNextPlayer(ptrToCurr, opponents);
						}
						players[ptrToCurr].placeBet(bigBlind);
						roundPot = roundPot + players[ptrToCurr].getBet();
						currBet = players[ptrToCurr].getBet();
					}	
					
					System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[0].getBet() + " for Big Blind");
				}	
				else {		// if it is an AI
					while( players[ptrToCurr].getMoney() < bigBlind){
						ptrToCurr = getNextPlayer(ptrToCurr, opponents);
					}
					players[ptrToCurr].placeBet( bigBlind );	// for now bets qrtr of his money
					roundPot = roundPot + players[ptrToCurr].getBet();
					currBet = players[ptrToCurr].getBet();
					System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[ptrToCurr].getBet() + " for Big Blind");
				}
				*/
			
				
				dealTwo( dealingPtr, ptrToDealer, bettingPtr, currBet, players, d, opponents);
				/*
				// all player are dealt two cards face down
				dealingPtr = getNextPlayer(ptrToDealer, opponents);   // start to left of the dealer
				// first to the left of the dealer who hasnt folded
				while(players[dealingPtr].getHasFolded())
					dealingPtr = getNextPlayer(ptrToDealer, opponents);
				bettingPtr = dealingPtr;
				int twice = 0;
				while ( twice != 2){
					// give cards only to those who havent folded
					if(!players[dealingPtr].getHasFolded()){
						players[dealingPtr].receiveCard(d.getNextCard());
						dealingPtr = getNextPlayer(dealingPtr, opponents);
					}
					else
						dealingPtr = getNextPlayer(dealingPtr, opponents);
					if( dealingPtr == ptrToDealer )
						twice++;
					if( twice == 2 && !players[dealingPtr].getHasFolded()){
						players[dealingPtr].receiveCard(d.getNextCard());
					}
				}
				System.out.println(" \nAll Players have been dealt 2 cards");
				if(!players[0].getHasFolded()){
					System.out.println("    Your cards are: ");
					System.out.println("       " + players[0].getHand().viewCard(0));
					System.out.println("       " + players[0].getHand().viewCard(1));
				}
				*/
				
				/////////////////////////////////////////////
				// round of betting goes here 
				System.out.println("\nround of betting begins here");
				ptrToCurr = getNextPlayer(ptrToCurr, opponents);
				currBet = roundOfBetting(players, currBet, opponents, ptrToCurr);
				//////////////////////////////////////////////
				
				
				dealFlop(d, ftr);
				/*
				// flop is placed on the table
				burn = d.getNextCard();
				ftr[0] = d.getNextCard();
				ftr[1] = d.getNextCard();
				ftr[2] = d.getNextCard();
				System.out.println("\n flop is   " + ftr[0].getNumber() + " of " + ftr[0].getSuit() + "   " + ftr[1].getNumber() + " of " + ftr[1].getSuit()+ "   " + ftr[2].getNumber()+ " of " + ftr[2].getSuit());
				*/
				
				
				/////////////////////////////////////////////
				// round of betting goes here 
				System.out.println("\nround of betting begins here");
				currBet = roundOfBetting(players, currBet, opponents, ptrToCurr);
				//////////////////////////////////////////////
				
				
				dealTurn(d, ftr);
				/*
				// turn is placed on table
				burn = d.getNextCard();
				ftr[3] = d.getNextCard();
				System.out.println("\nturn is placed on the table");
				System.out.println("     turn is: " + ftr[3].getNumber() + " of " + ftr[3].getSuit());
				*/
				
				/////////////////////////////////////////////
				// round of betting goes here 
				System.out.println("\nround of betting begins here");
				currBet = roundOfBetting(players, currBet, opponents, ptrToCurr);
				//////////////////////////////////////////////
				
			
				dealRiver(d, ftr);
				/*
				// river is placed on table
				burn = d.getNextCard();
				ftr[4] = d.getNextCard();
				System.out.println("\nriver is placedo on the table");
				System.out.println("     river is: " + ftr[4].getNumber() + " of " + ftr[4].getSuit());
				*/
				
				/////////////////////////////////////////////
				// round of betting goes here 
				System.out.println("\nround of betting begins here");
				currBet = roundOfBetting(players, currBet, opponents, ptrToCurr);
				//////////////////////////////////////////////
				
			
				showDown(players, opponents);
				/*
				///////////////////////////////////
				// everyone turns their cards face up
				System.out.println("\neveryone reveals their cards here");
				int showDown = 0;
				while(showDown < opponents+1){
					if(!players[showDown].getHasFolded()){
						System.out.println(players[showDown].getName() + " has \n" 
								+ "  " + players[showDown].getHand().viewCard(0).getNumber() + " of " + players[showDown].getHand().viewCard(0).getSuit() + "   " 
								+ "  " + players[showDown].getHand().viewCard(1).getNumber() + " of " + players[showDown].getHand().viewCard(1).getSuit());
					}
					showDown++;
				}
				/////////////////////////////////////
				*/
				
				/////////////////////////////////////////////////////
				// winner is declared and given pots money
				System.out.println("\nWinner is declared here");
				roundPot = 0;
				///////////////////////////////////////////////////////////
				
				
				resetAndPrep();
				/*
				// point to next person who will deal next round
				ptrToDealer = getNextPlayer(ptrToDealer, opponents);
				
				
				// reset all folders AND make sure there are at least three players who can remain in the game
				int remainingPlayers = 0;
				for(int resetter=0; resetter < opponents+1; resetter++){
					players[resetter].setFolded(false);
					players[resetter].setHasBet(false);
					if(players[resetter].getMoney() > bigBlind){
						remainingPlayers++;
					}
				}
				if ( remainingPlayers < 4){
					System.out.println("There are not enough players left at the table");
					quitRound = true;
				}
				
				// if you run out of money
				if(!(players[0].getMoney() > 0)){
					System.out.println("You have gone bankrupt, you lose");
					quitRound = true;
					quit = true;
				}
				// if you still have money ask about next round
				else{
					// another round prompt	
					System.out.println("Would you like to quit this game? \n (1) = no/another round (2) = yes/quit");
					s = br.readLine();
					resp = Integer.parseInt(s);
					if (resp == 2)
						quitRound = true;
				}
				*/
			}
		
			// in case bankrupt you just quit, otherwise ask
			if(!quit){
				System.out.println("Would you like to remain at this table and start a new game? \n (1) = yes (2) = no/quit");
				s = br.readLine();
				resp2 = Integer.parseInt(s);
				if (resp2 == 2)
					quit = true;
			}
		}
		
		System.out.println("\n Complete");
		*/
	}
	
	public static void getNumOpponenetsAndInitializePlayers(int opponents, Player user) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String s;
		System.out.println("How many opponents would you like to have at your table");
		s = br.readLine();
		opponents = Integer.parseInt(s);
		Player[] players = new Player[opponents+1];
	
		players[0] = user;
		// initialize opponents
		for ( int i = 1; i < opponents+1; i++){
			players[i] = new Player("Player" + i);
		}
	}
	
	public static void blinds(double smallBlind, double bigBlind, double currBet, Player[] players, int ptrToCurr, int opponents) throws IOException{
		String s;
		double b;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		// small blind
		ptrToCurr = getNextPlayer(ptrToCurr, opponents);
		if ( ptrToCurr == 0 ){ 	// if it is the user
			System.out.println("The Small blind is " + smallBlind + " would you like to enter (1), or fold now(2).");
			s = br.readLine();
			b = (double)Integer.parseInt(s);
			if ( b == 1 ){
				players[0].placeBet(smallBlind);
				roundPot = roundPot + players[0].getBet();
				currBet = players[0].getBet();
			}
			else
			{
				players[0].fold();
				System.out.println("You choose not enter this round");
				// find an ai that can do hte small blind isntead of the user
				// 		we are guaranteed to have at least 3 people
				while( players[ptrToCurr].getMoney() < smallBlind){
					ptrToCurr = getNextPlayer(ptrToCurr, opponents);
				}
				players[ptrToCurr].placeBet(smallBlind);
				roundPot = roundPot + players[ptrToCurr].getBet();
				currBet = players[ptrToCurr].getBet();
			}	
			
			System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[0].getBet() + " for Small Blind");
		}	
		else {		// if it is an AI
			while( players[ptrToCurr].getMoney() < smallBlind){
				ptrToCurr = getNextPlayer(ptrToCurr, opponents);
			}
			players[ptrToCurr].placeBet( smallBlind );	// for now bets qrtr of his money
			roundPot = roundPot + players[ptrToCurr].getBet();
			currBet = players[ptrToCurr].getBet();
			System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[ptrToCurr].getBet() + " for Small Blind");
		}
		
		
		// big blind 
		ptrToCurr = getNextPlayer(ptrToCurr, opponents);
		// if it is the user
		if ( ptrToCurr == 0 ){ 	// if it is the user
			System.out.println("The Big blind is " + bigBlind + " would you like to enter (1), or fold now(2).");
			s = br.readLine();
			b = (double)Integer.parseInt(s);
			if ( b == 1 ){
				players[0].placeBet(bigBlind);
				roundPot = roundPot + players[0].getBet();
				currBet = players[0].getBet();
			}
			else{
				players[0].fold();
				System.out.println("You choose not enter this round");
				// find an ai that can do hte small blind isntead of hte user
				// 		we are guaranteed to have at least 3 people
				while( players[ptrToCurr].getMoney() < bigBlind){
					ptrToCurr = getNextPlayer(ptrToCurr, opponents);
				}
				players[ptrToCurr].placeBet(bigBlind);
				roundPot = roundPot + players[ptrToCurr].getBet();
				currBet = players[ptrToCurr].getBet();
			}	
			
			System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[0].getBet() + " for Big Blind");
		}	
		else {		// if it is an AI
			while( players[ptrToCurr].getMoney() < bigBlind){
				ptrToCurr = getNextPlayer(ptrToCurr, opponents);
			}
			players[ptrToCurr].placeBet( bigBlind );	// for now bets qrtr of his money
			roundPot = roundPot + players[ptrToCurr].getBet();
			currBet = players[ptrToCurr].getBet();
			System.out.println("Player: " + players[ptrToCurr].getName() + " just put " + players[ptrToCurr].getBet() + " for Big Blind");
		}
		
	}
	
	public static void dealTwo(int dealingPtr, int ptrToDealer, int bettingPtr, double currBet, Player[] players, Deck d, int opponents ){
		// all player are dealt two cards face down
		dealingPtr = getNextPlayer(ptrToDealer, opponents);   // start to left of the dealer
		// first to the left of the dealer who hasnt folded
		while(players[dealingPtr].getHasFolded())
			dealingPtr = getNextPlayer(ptrToDealer, opponents);
		bettingPtr = dealingPtr;
		int twice = 0;
		while ( twice != 2){
			// give cards only to those who havent folded
			if(!players[dealingPtr].getHasFolded()){
				players[dealingPtr].receiveCard(d.getNextCard());
				dealingPtr = getNextPlayer(dealingPtr, opponents);
			}
			else
				dealingPtr = getNextPlayer(dealingPtr, opponents);
			if( dealingPtr == ptrToDealer )
				twice++;
			if( twice == 2 && !players[dealingPtr].getHasFolded()){
				players[dealingPtr].receiveCard(d.getNextCard());
			}
		}
		System.out.println(" \nAll Players have been dealt 2 cards");
		if(!players[0].getHasFolded()){
			System.out.println("    Your cards are: ");
			System.out.println("       " + players[0].getHand().viewCard(0));
			System.out.println("       " + players[0].getHand().viewCard(1));
		}
	}
	
	public static void dealFlop(Deck d, Card[] ftr){
		Card burn;
		// flop is placed on the table
		burn = d.getNextCard();
		ftr[0] = d.getNextCard();
		ftr[1] = d.getNextCard();
		ftr[2] = d.getNextCard();
		System.out.println("\n flop is   " + ftr[0].getNumber() + " of " + ftr[0].getSuit() + "   " + ftr[1].getNumber() + " of " + ftr[1].getSuit()+ "   " + ftr[2].getNumber()+ " of " + ftr[2].getSuit());
	}
	
	public static void dealTurn(Deck d, Card[] ftr){
		Card burn;
		// turn is placed on table
		burn = d.getNextCard();
		ftr[3] = d.getNextCard();
		System.out.println("\nturn is placed on the table");
		System.out.println("     turn is: " + ftr[3].getNumber() + " of " + ftr[3].getSuit());
		
	}
	
	public static void dealRiver(Deck d, Card[] ftr){
		Card burn;
		// river is placed on table
		burn = d.getNextCard();
		ftr[4] = d.getNextCard();
		System.out.println("\nriver is placedo on the table");
		System.out.println("     river is: " + ftr[4].getNumber() + " of " + ftr[4].getSuit());
		
	}
	
	public static void resetAndPrep(int ptrToDealer, int opponents, Player[] players, double bigBlind, double smallBlind, boolean quitRound, boolean quit) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String s;
		int resp;
		// point to next person who will deal next round
		ptrToDealer = getNextPlayer(ptrToDealer, opponents);
		
		
		// reset all folders AND make sure there are at least three players who can remain in the game
		int remainingPlayers = 0;
		for(int resetter=0; resetter < opponents+1; resetter++){
			players[resetter].setFolded(false);
			players[resetter].setHasBet(false);
			if(players[resetter].getMoney() > bigBlind){
				remainingPlayers++;
			}
		}
		if ( remainingPlayers < 4){
			System.out.println("There are not enough players left at the table");
			quitRound = true;
		}
		
		// if you run out of money
		if(!(players[0].getMoney() > 0)){
			System.out.println("You have gone bankrupt, you lose");
			quitRound = true;
			quit = true;
		}
		// if you still have money ask about next round
		else{
			// another round prompt	
			System.out.println("Would you like to quit this game? \n (1) = no/another round (2) = yes/quit");
			s = br.readLine();
			resp = Integer.parseInt(s);
			if (resp == 2)
				quitRound = true;
		}
	}
	
	public static int getNextPlayer(int ptr, int x){
		if(ptr == x)
			ptr = 0;
		else
			ptr++;
		return ptr;
	}
		
	public static double roundOfBetting(Player[] p, double currBet, int numOfOponents, int bettingPtr) throws IOException {
		String st;
		double bet;
		int checker = 0;
		boolean bettingDone = false;
		// betting pointer should point to the first person we want to get a bet from
		
		while(!bettingDone){
			// if the user is betting
			if(bettingPtr == 0 && !p[0].getHasFolded() && !p[0].getHasBet()){		
				System.out.println("Would you like to (1) call, (2) raise, (3) fold, or (4) check?");
				BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
				String r = br2.readLine();
				int resp = Integer.parseInt(r);
				
				// make sure user has enough money to play
				if(p[bettingPtr].getMoney() < currBet){
					resp = 3;
					System.out.println("You do not have enough money to continue this round.");
				}
				// if you only have enough to call
				if(p[bettingPtr].getMoney() == currBet){
					resp = 2;
					System.out.println("You only have enough money to call");
				}
				// call
				if( resp == 1 ){
					System.out.println(" you choose call");
					p[bettingPtr].placeBet(currBet);
					roundPot = roundPot + p[bettingPtr].getBet();
					currBet = p[bettingPtr].getBet();
					System.out.println("Player " + p[bettingPtr].getName() + " betted " + p[bettingPtr].getBet() );
				}
				// raise
				else if( resp == 2 ){
					System.out.println(" you choose raise");
					System.out.println("How much would you like to raise by?");
					st = br2.readLine();
					bet = (double)Integer.parseInt(st);
					p[bettingPtr].placeBet(currBet + bet);
					roundPot = roundPot + p[bettingPtr].getBet();
					currBet = p[bettingPtr].getBet();
					System.out.println("Player " + p[bettingPtr].getName() + " betted " + p[bettingPtr].getBet() );
				}	
				// fold
				else if( resp == 3 ){
					System.out.println(" you choose fold");
					p[bettingPtr].fold();
				}	
				// check we just let it go through to the next player
			}	
			// if ai is betting
			else if( !p[bettingPtr].getHasBet() && !p[bettingPtr].getHasFolded()){
				// if he has enough money to raise 1 dollar then he does
				if(p[bettingPtr].getMoney() >= currBet+1){
					p[bettingPtr].placeBet(currBet+1);
					roundPot = roundPot + p[bettingPtr].getBet();
					currBet = p[bettingPtr].getBet();
					System.out.println("Player " + p[bettingPtr].getName() + " betted " + p[bettingPtr].getBet() );
				}
				else
					p[bettingPtr].fold();
			}	
			
			
			// check if everyone has either bet or folded
			bettingDone = true;
			for(checker = 0; checker < numOfOponents+1; checker++){
				if(!p[checker].getHasBet() && !p[checker].getHasFolded()){
					bettingDone = false;
				}
			}
			
			bettingPtr = getNextPlayer(bettingPtr, numOfOponents);
		}
		
		// now we reset all the players has betted to false
		for(checker = 0; checker < numOfOponents+1; checker++){
			p[checker].setHasBet(false);
		}
		
		return currBet;
	}
	
	public static void showDown(Player[] players, int opponents){
		// everyone turns their cards face up
		System.out.println("\neveryone reveals their cards here");
		int showDown = 0;
		while(showDown < opponents+1){
			if(!players[showDown].getHasFolded()){
				System.out.println(players[showDown].getName() + " has \n" 
						+ "  " + players[showDown].getHand().viewCard(0).getNumber() + " of " + players[showDown].getHand().viewCard(0).getSuit() + "   " 
						+ "  " + players[showDown].getHand().viewCard(1).getNumber() + " of " + players[showDown].getHand().viewCard(1).getSuit());
			}
			showDown++;
		}
	}
	
	// returns a float denoting the likelihood of winning with the cards the hand has
	
	
}